package io.renren.modules.yckj.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.service.payments.model.Transaction;
import io.renren.common.page.PageData;
import io.renren.common.service.impl.CrudServiceImpl;
import io.renren.common.utils.ConvertUtils;
import io.renren.common.utils.Result;
import io.renren.modules.yckj.common.service.JsapiPayService;
import io.renren.modules.yckj.common.wx.JsapiType;
import io.renren.modules.yckj.dao.InvoiceLogsDao;
import io.renren.modules.yckj.dao.TeamDao;
import io.renren.modules.yckj.dao.TeamRelationDao;
import io.renren.modules.yckj.dao.UserDao;
import io.renren.modules.yckj.dto.AssetLogDTO;
import io.renren.modules.yckj.dto.InvoiceLogsDTO;
import io.renren.modules.yckj.dto.OrderDTO;
import io.renren.modules.yckj.entity.InvoiceLogsEntity;
import io.renren.modules.yckj.entity.OrderEntity;
import io.renren.modules.yckj.entity.TeamRelationEntity;
import io.renren.modules.yckj.enums.status.InvoiceStatus;
import io.renren.modules.yckj.enums.status.OrderStatus;
import io.renren.modules.yckj.enums.status.PayStatus;
import io.renren.modules.yckj.enums.type.AmountType;
import io.renren.modules.yckj.enums.type.AssetType;
import io.renren.modules.yckj.enums.type.PayWay;
import io.renren.modules.yckj.service.AssetLogService;
import io.renren.modules.yckj.service.InvoiceLogsService;
import io.renren.modules.yckj.service.OrderService;
import io.renren.modules.yckj.service.TeamRelationService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 发票日志
 *
 * @author Mark sunlightcs@gmail.com
 * @since 1.0.0 2025-05-20
 */
@Service
@AllArgsConstructor
public class InvoiceLogsServiceImpl extends CrudServiceImpl<InvoiceLogsDao, InvoiceLogsEntity, InvoiceLogsDTO> implements InvoiceLogsService {

    private final UserDao userDao;

    private final TeamDao teamDao;

    private final OrderService orderService;

    private final AssetLogService assetLogService;

    private final TeamRelationService teamRelationService;

    private final TeamRelationDao teamRelationDao;

    private final JsapiPayService jsapiPayService;

    @Override
    public QueryWrapper<InvoiceLogsEntity> getWrapper(Map<String, Object> params) {
        String id = (String) params.get("id");
        Object businessId = params.get("businessId");
        Object businessType = params.get("businessType");
        Object status = params.get("status");

        QueryWrapper<InvoiceLogsEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StrUtil.isNotBlank(id), "id", id);
        wrapper.eq(ObjectUtil.isAllNotEmpty(businessId), "business_id", businessId);
        wrapper.eq(ObjectUtil.isAllNotEmpty(businessType), "business_type", businessType);
        wrapper.eq(ObjectUtil.isAllNotEmpty(status), "status", status);

        return wrapper;
    }


    @Override
    public PageData<InvoiceLogsDTO> pageForApi(Map<String, Object> params) {
        //分页
        IPage<InvoiceLogsEntity> page = getPage(params, "id", false);
        //查询
        List<InvoiceLogsEntity> list = baseDao.getInvoiceLogList(params);

        return getPageData(list, page.getTotal(), InvoiceLogsDTO.class);
    }


    @Override
    public InvoiceLogsEntity getByUserIdBusiness(Long userId, Long businessId, Integer businessType) {
        Map<String, Object> params = new HashMap<>();
        params.put("userId", userId);
        params.put("businessId", businessId);
        params.put("businessType", businessType);
        return baseDao.getByUserIdBusiness(params);
    }

    @Override
    public Result handleOrderFinishedByAdmin(Long userId, Long businessId, Integer businessType) throws Exception {
        InvoiceLogsEntity dbInvoiceLogs = this.getByUserIdBusiness(userId, businessId, businessType);
        if (dbInvoiceLogs != null) {
            try {
                Transaction transaction = jsapiPayService.queryOrderByOutTradeNo(dbInvoiceLogs.getId().toString());
                if (transaction != null && transaction.getTradeState().equals(Transaction.TradeStateEnum.SUCCESS)) {
                    boolean b = this.handleNotify(dbInvoiceLogs.getId().toString(),
                            transaction.getTransactionId(),
                            JSONUtil.toJsonStr(transaction));
                    if (b) {
                        return new Result().success(0, "订单处理成功！");
                    } else {
                        return new Result().error(1, "订单处理失败，请联系管理员！");
                    }
                } else {
                    return new Result().error(1, "微信支付订单异常，请联系管理员！");
                }
            } catch (ServiceException e) {
                return new Result().error(1, "获取微信支付订单异常，请联系管理员！");
            }
        } else {
            return new Result().error(1, "订单处理失败，请联系管理员！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean handleNotify(String outTradeNo, String transactionId, String payData) throws Exception {
        InvoiceLogsDTO invoiceLogsDTO = this.get(Long.valueOf(outTradeNo));
        if (invoiceLogsDTO != null) {
            //更新微信支付状态
            InvoiceLogsEntity invoiceLogsEntity = new InvoiceLogsEntity();
            invoiceLogsEntity.setId(invoiceLogsDTO.getId());
            invoiceLogsEntity.setTransactionId(transactionId);
            invoiceLogsEntity.setInvoiceStatus(InvoiceStatus.INIT.getCode());
            invoiceLogsEntity.setPayResult(payData);
            invoiceLogsEntity.setStatus(PayStatus.PAYED.getCode());
            boolean b = this.updateById(invoiceLogsEntity);
            if (!b) {
                System.out.println("更新微信信息失败");
                throw new Exception("更新微信信息失败");
            }
            AssetLogDTO assetLogDTO = ConvertUtils.sourceToTarget(invoiceLogsDTO, AssetLogDTO.class);
            assetLogDTO.setId(null);
            assetLogDTO.setType(AssetType.RECHARGE.getCode());
            assetLogDTO.setCreateTime(new Date());
            assetLogDTO.setUpdateTime(new Date());
            if (invoiceLogsDTO.getBusinessType().equals(JsapiType.RECHARGE_USER.getCode())) {
                //充值 更新用户余额
                b = userDao.updateBalance(invoiceLogsDTO.getUserId(), invoiceLogsDTO.getAmount());
                if (!b) {
                    System.out.println("更新用户余额失败");
                    throw new Exception("更新用户余额失败");
                }
            } else if (invoiceLogsDTO.getBusinessType().equals(JsapiType.RECHARGE_TEAM.getCode())) {
                //充值 更新组余额
                b = teamDao.updateBalance(invoiceLogsDTO.getBusinessId(), invoiceLogsDTO.getAmount());
                if (!b) {
                    System.out.println("更新用户组余额失败");
                    throw new Exception("更新用户组余额失败");
                }
            } else if (invoiceLogsDTO.getBusinessType().equals(JsapiType.PAY.getCode())) {
                //订单支付
                assetLogDTO.setType(AssetType.PAY.getCode());
                //以下为订单支付完成后，状态修改
                OrderDTO dbOrderDto = orderService.get(invoiceLogsDTO.getBusinessId());
                if (dbOrderDto != null) {
                    //更新订单状态
                    OrderEntity orderEntity = new OrderEntity();
                    orderEntity.setId(invoiceLogsDTO.getBusinessId());
                    orderEntity.setStatus(OrderStatus.FINISHED.getCode());
                    orderEntity.setPayWay(PayWay.WX.getCode());
                    b = orderService.updateById(orderEntity);
                    if (!b) {
                        System.out.println("更新订单状态失败");
                        throw new Exception("更新订单状态失败");
                    }
                    //组订单 个人支付
                    if (dbOrderDto.getTeamId() != null && dbOrderDto.getTeamId() > 0) {
                        //更新组限额
                        BigDecimal debtLimitUse = dbOrderDto.getActualAmount().multiply(new BigDecimal(-1));
                        b = teamDao.updateDebtLimitUse(dbOrderDto.getTeamId(), debtLimitUse);
                        if (!b) {
                            System.out.println("更新组限额失败");
                            throw new Exception("更新组限额失败");
                        }
                        //更新组内个人限额
                        TeamRelationEntity teamRelation = teamRelationService.getByTeamIdAndUserId(dbOrderDto.getTeamId(), dbOrderDto.getUserId());
                        if (teamRelation != null) {
                            if (teamRelation.getAmountPower().equals(AmountType.FIXED.getCode())
                                    || teamRelation.getAmountPower().equals(AmountType.ALL.getCode())) {
                                b = teamRelationDao.updateDebtLimitUse(teamRelation.getId(), debtLimitUse);
                                if (!b) {
                                    System.out.println("更新用户限额失败");
                                    throw new Exception("更新用户限额失败");
                                }
                            }
                        } else {
                            System.out.println("当前用户不在当前组内");
                            throw new Exception("当前用户不在当前组内");
                        }
                    } else {
                        //个人订单 更新用户限额
                        BigDecimal debtLimitUse = dbOrderDto.getActualAmount().multiply(new BigDecimal(-1));
                        b = userDao.updateDebtLimitUse(dbOrderDto.getUserId(), debtLimitUse);
                        if (!b) {
                            System.out.println("更新用户限额失败");
                            throw new Exception("更新用户限额失败");
                        }
                    }
                } else {
                    System.out.println("订单不存在");
                    throw new Exception("订单不存在");
                }
            }
            //保存日志
            try {
                b = assetLogService.save(assetLogDTO);
            } catch (Exception e) {
                System.out.println("保存用户资产记录失败");
                throw new Exception("保存用户资产记录失败");
            }
            return b;
        } else {
            System.out.println("当前业务数据错误");
            throw new Exception("当前业务数据错误");
        }
    }


}